package bbs.controller;

import bbs.annotation.GlobalInterceptor;
import bbs.annotation.VerifyParam;
import bbs.controller.base.ABaseController;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.HashMap;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import bbs.entity.config.WebConfig;
import bbs.entity.constants.Constants;
import bbs.entity.enums.ResponseCodeEnum;
import bbs.entity.enums.UserOperFrequencyTypeEnum;
import bbs.entity.vo.ResponseVO;
import bbs.exception.BusinessException;
import bbs.utils.StringTools;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController("fileController")
@RequestMapping({"/file"})
public class FileController extends ABaseController {

    private static final Logger logger = LoggerFactory.getLogger(FileController.class);

    @Resource
    private WebConfig webConfig;

    @RequestMapping({"/uploadImage"})
    @GlobalInterceptor(checkLogin = true, frequencyType = UserOperFrequencyTypeEnum.IMAGE_UPLOAD)
    public ResponseVO uploadImage(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        String fileExtName = StringTools.getFileSuffix(fileName);
        if (!ArrayUtils.contains((Object[]) Constants.IMAGE_SUFFIX, fileExtName))
            throw new BusinessException(ResponseCodeEnum.CODE_600);

        String path = copyFile(file);
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put("fileName", path);
        return getSuccessResponseVO(hashMap);
    }

    private String copyFile(MultipartFile paramMultipartFile) {
        try {
            String fileName = paramMultipartFile.getOriginalFilename();
            String fileExtName =  StringTools.getFileSuffix(fileName);
            String fileRealName = StringTools.getRandomString(Constants.LENGTH_30) + fileExtName;
            String folderPath = this.webConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + Constants.FILE_FOLDER_TEMP;

            File folder = new File(folderPath);
            if (!folder.exists())
                folder.mkdirs();

            File uploadFile =  new File(folderPath + "/" + fileRealName);
            paramMultipartFile.transferTo(uploadFile);
            return "temp/" + fileRealName;
        } catch (Exception exception) {
            logger.error(Constants.FILE_UPDATE_ERROR, exception);
            throw new BusinessException(Constants.FILE_UPDATE_ERROR);
        }
    }

    /**
     * 获取头像
     * @param response
     * @param userId
     */
    @RequestMapping({"/getAvatar/{userId}"})
    @GlobalInterceptor(checkLogin = false, checkParams = true)
    public void getAvatar(HttpServletResponse response, @VerifyParam(required = true) @PathVariable("userId") String userId) {
        String avatarFolderName = Constants.FILE_FOLDER_FILE + Constants.FILE_FOLDER_AVATAR_NAME;
        String avatarPath = this.webConfig.getProjectFolder() + avatarFolderName + userId + Constants.AVATAR_SUFFIX;
        File avatarFolder = new File(avatarFolderName);

        if (!avatarFolder.exists()) avatarFolder.mkdirs();

        File file = new File(avatarPath);
        String imageName = userId + Constants.AVATAR_SUFFIX;
        if(!file.exists()) imageName = Constants.AVATAR_DEFAULT;
        readImage(response, Constants.FILE_FOLDER_AVATAR_NAME, imageName);
    }

    @RequestMapping({"/getImage/{imageFolder}/{imageName}"})
    public void getImage(HttpServletResponse response, @PathVariable("imageFolder") String imageFolder, @PathVariable("imageName") String imageName) {
        readImage(response, imageFolder, imageName);
    }


    /**
     * 读取并输出图片到HTTP响应
     *
     * @param paramHttpServletResponse HTTP响应对象，用于输出图片内容
     * @param paramString1 图片的目录名称，用于定位图片存储路径
     * @param paramString2 图片的文件名称及路径，用于定位图片存储路径
     */
    private void readImage(HttpServletResponse paramHttpServletResponse, String paramString1, String paramString2) {
        ServletOutputStream servletOutputStream = null;
        FileInputStream fileInputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            // 检查参数是否有效
            if (StringTools.isEmpty(paramString1) || StringUtils.isBlank(paramString2))
                return;

            // 获取图片后缀名，用于设置响应内容类型
            String imageSuffix = StringTools.getFileSuffix(paramString2);
            // 构建图片文件路径
            String filePath = this.webConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + "images/" + paramString1 + "/" + paramString2;
            if ("temp".equals(paramString1) || paramString1.contains(Constants.FILE_FOLDER_AVATAR_NAME)) {
                filePath = this.webConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + paramString1 + "/" + paramString2;
            }
//            else if (paramString1.contains("avatar/")) {
//                filePath = this.webConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + paramString1 + paramString2;
//            }

            File file = new File(filePath);
            // 如果文件不存在，则直接返回
            if (!file.exists())
                return;

            // 移除文件后缀名中的点字符
            imageSuffix = imageSuffix.replace(".", "");
            // 设置响应缓存头，除了临时文件和头像外，其他图片缓存30天
            if (!"avatar/".equals(paramString1))
                paramHttpServletResponse.setHeader("Cache-Control", "max-age=2592000");
            // 设置响应的内容类型为图片类型
            paramHttpServletResponse.setContentType("image/" + imageSuffix);

            // 使用FileInputStream读取图片文件
            fileInputStream = new FileInputStream(file);
            // 获取HTTP响应的输出流，用于向客户端输出图片内容
            servletOutputStream = paramHttpServletResponse.getOutputStream();
            // 使用ByteArrayOutputStream暂存图片内容
            byteArrayOutputStream = new ByteArrayOutputStream();

            int i = 0;
            // 读取文件内容到ByteArrayOutputStream
            while (-1 != (i = fileInputStream.read()))
                byteArrayOutputStream.write(i);
            // 将图片内容输出到HTTP响应
            servletOutputStream.write(byteArrayOutputStream.toByteArray());
        } catch (Exception exception) {
            // 记录异常日志
            logger.error("图片读取异常", exception);
        } finally {
            // 关闭资源
            if (byteArrayOutputStream != null)
                try {
                    byteArrayOutputStream.close();
                } catch (IOException iOException) {
                    iOException.printStackTrace();
                }
            if (servletOutputStream != null)
                try {
                    servletOutputStream.close();
                } catch (IOException iOException) {
                    logger.error("IO异常", iOException);
                }
            if (fileInputStream != null)
                try {
                    fileInputStream.close();
                } catch (IOException iOException) {
                    logger.error("IO异常", iOException);
                }
        }
    }

}
